home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / DCPGPKT.C < prev    next >
C/C++ Source or Header  |  1991-11-17  |  35KB  |  1,057 lines

  1. /*
  2.    For best results in visual layout while viewing this file, set
  3.    tab stops to every 4 columns.
  4. */
  5.  
  6. /*
  7.    dcpgpkt.c
  8.  
  9.    Revised edition of dcp
  10.  
  11.    Stuart Lynne May/87
  12.  
  13.    Copyright (c) Richard H. Lamb 1985, 1986, 1987
  14.    Changes Copyright (c) Stuart Lynne 1987
  15.  
  16.    Maintenance notes:
  17.  
  18.    25Aug87 - Allow for up to 7 windows - Jal
  19.    01Nov87 - those strncpy's should really be memcpy's! - Jal
  20.    11Sep89 - Raise TimeOut to 15 - ahd
  21.    30Apr90 - Add Jordon Brown's fix for short packet retries.
  22.              Reduce retry limit to 20                             ahd
  23.    22Jul90 - Change error retry limit from per host to per
  24.              packet.                                              ahd
  25.    22Jul90 - Add error message for number of retries exceeded     ahd
  26.    08Sep90 - Drop memmove to memcpy change supplied by Jordan
  27.              Brown, MS 6.0 and Turbo C++ agree memmove insures
  28.              no overlap
  29. */
  30.  
  31. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  32.  
  33. /* 7-window "g" ptotocol */
  34.  
  35. /*
  36.    Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
  37.    UUCP protocol description -- Obviously invaluable.
  38.    Thanks also go to Andrew Tannenbaum for the section on Siding window
  39.    protocols with a program example in his "Computer Networks" book.
  40. */
  41.  
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <time.h>
  45.  
  46. #include "lib.h"
  47. #include "dcp.h"
  48. #include "dcpsys.h"
  49. #include "dcpgpkt.h"
  50. #include "hostable.h"
  51. #include "security.h"
  52. #include "ulib.h"
  53. #include "modem.h"
  54.  
  55. #define PKTSIZE   64
  56. #define PKTSIZ2   2  /* 8x(2**2) = 64 */
  57.  
  58. #define HDRSIZE   6
  59. #define MAXTRY 4
  60.  
  61. /*--------------------------------------------------------------------*/
  62. /*                     g-packet type definitions                      */
  63. /*--------------------------------------------------------------------*/
  64.  
  65. #define DATA   0
  66. #define CLOSE  1
  67. #define NAK    2
  68. #define SRJ    3
  69. #define ACK    4
  70. #define INITC  5
  71. #define INITB  6
  72. #define INITA  7
  73.  
  74. #define POK    -1
  75.  
  76. #define MAXWINDOW 7
  77. #define NBUF   8              /* always SAME as MAXSEQ ? */
  78. #define MAXSEQ 8
  79.  
  80. #define between(a,b,c) ((a<=b && b<c) || \
  81.                         (c<a && a<=b) || \
  82.                         (b<c && c<a))
  83.  
  84. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  85.  
  86. /*--------------------------------------------------------------------*/
  87. /*              Global variables for packet definitions               */
  88. /*--------------------------------------------------------------------*/
  89.  
  90. static int rwl, swl, swu, rwu, nbuffers, irec, lazynak;
  91. static INTEGER nerr;
  92. static int outlen[NBUF], inlen[NBUF], arrived[NBUF];
  93. static int nwindows, maxwindows;
  94. static char outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
  95. static long ftimer[NBUF];
  96. static int timeouts, outsequence, naksin, naksout, screwups;
  97. static int reinit, shifts, badhdr, resends;
  98.  
  99. /*--------------------------------------------------------------------*/
  100. /*                    Internal function prototypes                    */
  101. /*--------------------------------------------------------------------*/
  102.  
  103. static int  gmachine(const int timeout);
  104. static void gspack(int  type,int  yyy,int  xxx,int  len,char  *data);
  105. static int  grpack(int  *yyy,
  106.                    int  *xxx,
  107.                    int  *len,
  108.                    char  *data,
  109.                    const int timeout);
  110. static void gstats( void );
  111.  
  112. static unsigned int checksum(char *data, int len);
  113.  
  114. /****************** SUB SUB SUB PACKET HANDLER ************/
  115.  
  116. /*
  117.    g o p e n p k
  118. */
  119.  
  120. int gopenpk()
  121. {
  122.    int i, xxx, yyy, len;
  123.    char tmp[PKTSIZE+1];
  124.  
  125.    pktsize = PKTSIZE;   /* change it later after the init */
  126.    maxwindows = GetGWindow( MAXWINDOW );
  127.  
  128. /*--------------------------------------------------------------------*/
  129. /*                     Initialize error counters                      */
  130. /*--------------------------------------------------------------------*/
  131.  
  132.    timeouts = outsequence = naksin = naksout = screwups =
  133.       shifts = badhdr = resends = reinit = 0;
  134.  
  135. /*--------------------------------------------------------------------*/
  136. /*                    Initialize proto parameters                     */
  137. /*--------------------------------------------------------------------*/
  138.  
  139.    nerr = nbuffers = 0;
  140.    swl = swu = 1;
  141.    rwl = 0;
  142.    nwindows = maxwindows;
  143.    rwu = nwindows - 1;
  144.    if ( PortTimeout == 0 )
  145.       PortTimeout = PacketTimeout * 2 - 1;
  146.    for (i = 0; i < NBUF; i++) {
  147.       ftimer[i] = 0;
  148.       arrived[i] = FALSE;
  149.    }
  150.  
  151. /*--------------------------------------------------------------------*/
  152. /*                          3-way handshake                           */
  153. /*--------------------------------------------------------------------*/
  154.  
  155.    gspack(INITA, 0, 0, 0, tmp);
  156. rsrt:
  157.    if (nerr >= MaxErr)
  158.    {
  159.       remote_stats.errors += nerr;
  160.       nerr = 0;
  161.       printmsg(0,
  162.          "gopenpk: Consecutive error limit of %ld exceeded, %ld total errors",
  163.           (long) MaxErr, remote_stats.errors);
  164.       return(FAILED);
  165.    }
  166.  
  167. /*--------------------------------------------------------------------*/
  168. /*    INIT sequence.  Easy fix for variable packet size.  I didn't    */
  169. /*    since all the machines I talk to use PKTSZ=64.  If you do       */
  170. /*    this make sure to reflect the changes in "grpack" and           */
  171. /*    "gspack"                                                        */
  172. /*--------------------------------------------------------------------*/
  173.  
  174.    switch (grpack(&yyy, &xxx, &len, tmp, PacketTimeout )) {
  175.    case INITA:
  176.       printmsg(5, "**got INITA");
  177.       nwindows = yyy;
  178.       if (nwindows > maxwindows)
  179.          nwindows = maxwindows;
  180.       rwu = nwindows - 1;
  181.       gspack(INITB, 0, 0, 0, tmp);  /* data segment (packet) size */
  182.       goto rsrt;
  183.    case INITB:
  184.       printmsg(5, "**got INITB");
  185.       gspack(INITC, 0, 0, 0, tmp);
  186.       goto rsrt;
  187.    case INITC:
  188.       printmsg(5, "**got INITC");
  189.       break;
  190.    default:
  191.       nerr++;
  192.       screwups++;
  193.       printmsg(5, "**got SCREW UP");
  194.       gspack(INITA, 0, 0, 0, tmp);
  195.       goto rsrt;
  196.    }
  197.  
  198.    nerr = 0;
  199.    lazynak = 0;
  200.    return(OK); /* channel open */
  201.  
  202. } /*gopenpk*/
  203.  
  204. /*--------------------------------------------------------------------*/
  205. /*    g f i l e p k t                                                 */
  206. /*                                                                    */
  207. /*    Begin a file transfer (not used by "g" protocol)                */
  208. /*--------------------------------------------------------------------*/
  209.  
  210. int gfilepkt( void )
  211. {
  212.    return OK;
  213. } /* gfilepkt */
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*    g c l o s e p k                                                 */
  217. /*                                                                    */
  218. /*    Close packet machine                                            */
  219. /*--------------------------------------------------------------------*/
  220.  
  221. int gclosepk()
  222. {
  223.    int i;
  224.    char tmp[PKTSIZE+1];
  225.  
  226.    for (i = 0; i < MAXTRY; i++) {
  227.       gspack(CLOSE, 0, 0, 0, tmp);
  228.       if (gmachine(PacketTimeout) == CLOSE)
  229.          break;
  230.    }
  231.  
  232.    gstats();
  233.    return(0);
  234.  
  235. } /*gclosepk*/
  236.  
  237. /*--------------------------------------------------------------------*/
  238. /*    g s t a t s                                                     */
  239. /*                                                                    */
  240. /*    Report summary of errors for processing                         */
  241. /*--------------------------------------------------------------------*/
  242.  
  243. static void gstats( void )
  244. {
  245.    remote_stats.errors += nerr;
  246.    nerr = 0;
  247.    if ( remote_stats.errors || shifts || badhdr )
  248.    {
  249.       printmsg(0,
  250.          "%d time outs, %d port reinits, %d out of seq pkts, \
  251. %d NAKs rec, %d NAKs sent",
  252.             timeouts, reinit, outsequence, naksin, naksout);
  253.       printmsg(0,
  254.          "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
  255.             screwups, shifts, badhdr, resends);
  256.    }
  257. }
  258.  
  259. /*
  260.    g g e t p k t
  261.  
  262.    Gets no more than a packet's worth of data from
  263.    the "packet I/O state machine".  May have to
  264.    periodically run the packet machine to get some packets.
  265.  
  266.    on input:   don't care
  267.    on return:  data+\0 and length in len.
  268.  
  269.    ret(0)   if all's well
  270.    ret(-1) if problems (failed)
  271. */
  272.  
  273. int ggetpkt(char *data, int *len)
  274. {
  275.    int   i;
  276.    int   retry = MaxErr;
  277.    time_t start;
  278. #ifdef _DEBUG
  279.    int savedebug = debuglevel;
  280. #endif
  281.  
  282.    irec = 1;
  283.    time( &start );
  284.  
  285. /*--------------------------------------------------------------------*/
  286. /*                Loop to wait for the desired packet                 */
  287. /*--------------------------------------------------------------------*/
  288.  
  289.    while (!arrived[rwl] && retry)
  290.    {
  291.       if (gmachine(PacketTimeout) != POK)
  292.          return(-1);
  293.  
  294.       if (!arrived[rwl] )
  295.       {
  296.          time_t now;
  297.          if (time( &now ) > (start + PacketTimeout) )
  298.          {
  299. #ifdef _DEBUG
  300.             if ( debuglevel < 6 )
  301.                debuglevel = 6;
  302. #endif
  303.             printmsg(5,"ggetpkt: Timeout %d waiting for inbound packet %d",
  304.                      MaxErr - --retry, remote_stats.packets + 1);
  305.             timeouts++;
  306.             start = now;
  307.          } /* if (time( now ) > (start + PacketTimeout) ) */
  308.       } /* if (!arrived[rwl] ) */
  309.    } /* while (!arrived[rwl] && i) */
  310.  
  311. #ifdef _DEBUG
  312.    debuglevel = savedebug;
  313. #endif
  314.  
  315.    if (!arrived[rwl])
  316.    {
  317.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  318.                (long) PacketTimeout * MaxErr);
  319.       gclosepk();
  320.       return -1;
  321.    }
  322.  
  323. /*--------------------------------------------------------------------*/
  324. /*                           Got a packet!                            */
  325. /*--------------------------------------------------------------------*/
  326.  
  327.    i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
  328.    *len = inlen[i];
  329.    memcpy(data, inbuf[i], *len);
  330.  
  331.    arrived[i] = FALSE;
  332.    rwu = nextpkt(rwu)        ;  /* bump receive window */
  333.  
  334.    return(0);
  335.  
  336. } /*ggetpkt*/
  337.  
  338.  
  339. /*
  340.    g s e n d p k t
  341.  
  342.    Put at most a packet's worth of data in the packet state
  343.    machine for transmission.
  344.    May have to run the packet machine a few times to get
  345.    an available output slot.
  346.  
  347.    on input: data=*data; len=length of data in data.
  348.  
  349.    return:
  350.     0 if all's well
  351.    -1 if problems (failed)
  352. */
  353.  
  354. int gsendpkt(char *data, int len)
  355. {
  356.    int i1;
  357. #ifdef _DEBUG
  358.    int savedebug = debuglevel;
  359. #endif
  360.  
  361.    irec = 0;
  362.    /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
  363.       acked, wait for acks */
  364.    while (nbuffers >= nwindows)
  365.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  366.          return(-1);
  367.  
  368.    i1 = swu;   /* <--If we ever have more than 8 seq no.s, must mod() here */
  369.  
  370. /*--------------------------------------------------------------------*/
  371. /*               Place packet in table and mark unacked               */
  372. /*--------------------------------------------------------------------*/
  373.  
  374.    memcpy(outbuf[i1], data, len);
  375.  
  376. /*--------------------------------------------------------------------*/
  377. /*                       Handle short packets.                        */
  378. /*--------------------------------------------------------------------*/
  379.  
  380.    if(len < PKTSIZE) {
  381.       memmove(outbuf[i1] + 1, outbuf[i1], PKTSIZE - 1);
  382.       outbuf[i1][0] = (unsigned char) (PKTSIZE - len);
  383.       memset(outbuf[i1]+len+1, 0, PKTSIZE-len-1);
  384.                               /* Pad with nulls.  Ugh.               */
  385.    }
  386.  
  387. /*--------------------------------------------------------------------*/
  388. /*                            Mark packet                             */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.    outlen[i1] = len;
  392.    ftimer[i1] = time(nil(long));
  393.    swu = nextpkt(swu);  /* bump send window */
  394.    nbuffers++;
  395.  
  396. /*--------------------------------------------------------------------*/
  397. /*                              send it                               */
  398. /*--------------------------------------------------------------------*/
  399.  
  400.    gspack(DATA, rwl, i1, outlen[i1], outbuf[i1]);
  401.  
  402. #ifdef _DEBUG
  403.    debuglevel = savedebug;
  404. #endif
  405.  
  406.    return(0);
  407.  
  408. } /*gsendpkt*/
  409.  
  410.  
  411. /*--------------------------------------------------------------------*/
  412. /*    g e o f p k t                                                   */
  413. /*                                                                    */
  414. /*    Transmit EOF to the other system                                */
  415. /*--------------------------------------------------------------------*/
  416.  
  417. int geofpkt( void )
  418. {
  419.    char outbuf[PKTSIZE+1];
  420.    if (gsendpkt(outbuf, 0))   /* Empty packet == EOF              */
  421.       return FAILED;
  422.    else
  423.       return OK;
  424. } /* geofpkt */
  425.  
  426. /*--------------------------------------------------------------------*/
  427. /*    g w r m s g                                                     */
  428. /*                                                                    */
  429. /*    Send a message to remote system                                 */
  430. /*--------------------------------------------------------------------*/
  431.  
  432. int gwrmsg( char *s )
  433. {
  434.    for(; strlen(s) >= pktsize; s += pktsize) {
  435.       int result = gsendpkt(s, pktsize);
  436.       if (result)
  437.          return result;
  438.    }
  439.  
  440.    return gsendpkt(s, strlen(s)+1);
  441. } /* gwrmsg */
  442.  
  443. /*--------------------------------------------------------------------*/
  444. /*    g r d m s g                                                     */
  445. /*                                                                    */
  446. /*    Read a message from the remote system                           */
  447. /*--------------------------------------------------------------------*/
  448.  
  449. int grdmsg( char *s)
  450. {
  451.    for ( ;; )
  452.    {
  453.       int len;
  454.       int result = ggetpkt( s, &len );
  455.       if (result || (s[len-1] == '\0'))
  456.          return result;
  457.       s += len;
  458.    } /* for */
  459.  
  460. } /* grdmsg */
  461.  
  462. /**********  Packet Machine  ********** RH Lamb 3/87 */
  463.  
  464. /*--------------------------------------------------------------------*/
  465. /*    g m a c h i n e                                                 */
  466. /*                                                                    */
  467. /*    Ideally we would like to fork this process off in an            */
  468. /*    infinite loop and send and receive packets through "inbuf"      */
  469. /*    and "outbuf".  Can't do this in MS-DOS so we setup "getpkt"     */
  470. /*    and "sendpkt" to call this routine often and return only        */
  471. /*    when the input buffer is empty thus "blocking" the packet-      */
  472. /*    machine task.                                                   */
  473. /*--------------------------------------------------------------------*/
  474.  
  475. static int gmachine(const int timeout )
  476. {
  477.    static time_t idletimer = 0;
  478.    static time_t acktimer  = 0;
  479.  
  480.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  481.    boolean close  = FALSE;    /* True = terminate connection upon
  482.                                         exit                      */
  483.    boolean inseq  = TRUE;     /* True = Count next out of sequence
  484.                                         packet as an error           */
  485.    char rdata[PKTSIZE+1];
  486.  
  487.    while ( !done )
  488.    {
  489.       boolean resend = FALSE;    /* True = resend data packets       */
  490.       boolean donak  = FALSE;    /* True = NAK the other system      */
  491.       unsigned long packet_no = remote_stats.packets;
  492.  
  493.       int pkttype, rack, rseq, rlen, i1;
  494.       time_t now;
  495.  
  496.       if ( debuglevel >= 7 )     /* Optimize processing a little bit */
  497.       {
  498.          printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
  499.             swl, swu, rwl, rwu, nerr);
  500.  
  501. /*--------------------------------------------------------------------*/
  502. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  503. /*    rwl=expected pkt                                                */
  504. /*--------------------------------------------------------------------*/
  505.  
  506.          printmsg(7, "Bytes transfered %ld errors %d",
  507.             (long) (remote_stats.packets * PKTSIZE) , nerr);
  508.       }
  509.  
  510. /*--------------------------------------------------------------------*/
  511. /*             Attempt to retrieve a packet and handle it             */
  512. /*--------------------------------------------------------------------*/
  513.  
  514.       pkttype = grpack(&rack, &rseq, &rlen, rdata, timeout);
  515.       time(&now);
  516.       switch (pkttype) {
  517.  
  518.          case CLOSE:
  519.             remote_stats.packets++;
  520.             printmsg(5, "**got CLOSE");
  521.             close = done = TRUE;
  522.             break;
  523.  
  524.          case EMPTY:
  525.             printmsg(6, "**got EMPTY");
  526.             if (acktimer && (acktimer <= (now - PortTimeout)))
  527.             {
  528.                printmsg(5,"*** port re-init");
  529.                reinit++;
  530.                flowcontrol( FALSE );
  531.                acktimer = now;
  532.             }
  533.  
  534.             if (ftimer[swl])
  535.             {
  536.                printmsg(6, "---> seq, elapst %d %ld", swl,
  537.                     ftimer[swl] - now);
  538.                if ( ftimer[swl] <= (now - PacketTimeout))
  539.                {
  540.                    printmsg(4, "*** timeout %d (%ld)",
  541.                                swl, (long) remote_stats.packets);
  542.                        /* Since "g" is "go-back-N", when we time out we
  543.                           must send the last N pkts in order.  The generalized
  544.                           sliding window scheme relaxes this reqirment. */
  545.                    nerr++;
  546.                    timeouts++;
  547.                    resend = TRUE;
  548.                } /* if */
  549.             } /* if */
  550.             else if (now > (idletimer + PacketTimeout))
  551.                printmsg(2,"*** BORED");
  552.  
  553.             done = TRUE;
  554.             break;
  555.  
  556.          case DATA:
  557.             printmsg(5, "**got DATA %d %d", rack, rseq);
  558.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  559.             if (i1 == rseq) {
  560.                lazynak--;
  561.                remote_stats.packets++;
  562.                idletimer = now;
  563.                inseq = arrived[i1] = TRUE;
  564.                inlen[i1] = rlen;
  565.                memcpy(inbuf[i1], rdata, rlen);
  566.                rwl = i1;
  567.                printmsg(5, "*** ACK d %d", rwl);
  568.                gspack(ACK, rwl, 0, 0, rdata);
  569.                done = TRUE;   /* return to caller when finished      */
  570.                               /* in a mtask system, unneccesary      */
  571.             } else {
  572.                if (inseq || ( now > (idletimer + PacketTimeout)))
  573.                {
  574.                   donak = TRUE;  /* Only flag first out of sequence
  575.                                     packet as error, since we know
  576.                                     following ones also bad             */
  577.                   outsequence++;
  578.                   inseq = FALSE;
  579.                }
  580.                printmsg(5, "*** unexpect %d ne %d (%d - %d)",
  581.                                        rseq, i1, rwl, rwu);
  582.             } /* else */
  583.  
  584.             if ( swl == swu )       /* We waiting for an ACK?     */
  585.                break;               /* No --> Skip ACK processing */
  586.             /* else Fall through to ACK case */
  587.  
  588.          case NAK:
  589.          case ACK:
  590.             if (pkttype == NAK)
  591.             {
  592.                nerr++;
  593.                naksin++;
  594.                printmsg(5, "**got NAK %d", rack);
  595.                resend = TRUE;
  596.             }
  597.             else if (pkttype == ACK)
  598.                printmsg(5, "**got ACK %d", rack);
  599.             acktimer = now;
  600.  
  601.             while(between(swl, rack, swu))
  602.             {                             /* S<-- -->(S+W-1)%8 */
  603.                remote_stats.packets++;
  604.                printmsg(5, "*** ACK %d", swl);
  605.                ftimer[swl] = 0;
  606.                idletimer = acktimer;
  607.                nbuffers--;
  608.                done = TRUE;            /* Get more data for input */
  609.                swl = nextpkt(swl);
  610.             } /* while */
  611.  
  612.             if (!done && (pkttype == ACK)) /* Find packet?         */
  613.             {
  614.                printmsg(0,"*** ACK for bad packet %d (%d - %d)",
  615.                            rack, swl, swu);
  616.             } /* if */
  617.             break;
  618.  
  619.          case ERROR:
  620.             printmsg(5, "*** got BAD CHK");
  621.             acktimer = now;
  622.             naksout++;
  623.             donak = TRUE;
  624.             lazynak = 0;               /* Always NAK bad checksum */
  625.             break;
  626.  
  627.          default:
  628.             screwups++;
  629.             nerr++;
  630.             printmsg(5, "*** got SCREW UP");
  631.             break;
  632.  
  633.       } /* switch */
  634.  
  635. /*--------------------------------------------------------------------*/
  636. /*      If we received an NAK or timed out, resend data packets       */
  637. /*--------------------------------------------------------------------*/
  638.  
  639.       if ( resend )
  640.       for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
  641.       {                          /* resend rack->(swu-1)             */
  642.          resends++;
  643.          gspack(DATA, rwl, rack, outlen[rack], outbuf[rack]);
  644.          printmsg(5, "*** resent %d", rack);
  645.          idletimer = ftimer[rack] = now;
  646.       } /* for */
  647.  
  648. /*--------------------------------------------------------------------*/
  649. /*  If we have an error and have not recently sent a NAK, do so now.  */
  650. /*  We then reset our counter so we receive at least a window full of */
  651. /*                 packets before sending another NAK                 */
  652. /*--------------------------------------------------------------------*/
  653.  
  654.       if ( donak )
  655.       {
  656.          nerr++;
  657.          if ( (lazynak < 1) || (now > (idletimer + PacketTimeout)))
  658.          {
  659.             printmsg(5, "*** NAK d %d", rwl);
  660.             gspack(NAK, rwl, 0, 0, rdata);
  661.             naksout++;
  662.             idletimer = now;
  663.             lazynak = nwindows + 1;
  664.          } /* if ( lazynak < 1 ) */
  665.       } /* if ( donak ) */
  666.  
  667. /*--------------------------------------------------------------------*/
  668. /*                   Update error counter if needed                   */
  669. /*--------------------------------------------------------------------*/
  670.  
  671.       if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
  672.       {
  673.          printmsg(2,"gmachine: Packet %ld had %ld errors during transfer",
  674.                      remote_stats.packets, (long) nerr);
  675.          remote_stats.errors += nerr;
  676.          nerr = 0;
  677.       }
  678.  
  679. /*--------------------------------------------------------------------*/
  680. /*    If we have an excessive number of errors, drop out of the       */
  681. /*    loop                                                            */
  682. /*--------------------------------------------------------------------*/
  683.  
  684.       if (nerr >= MaxErr)
  685.       {
  686.          printmsg(0,
  687.             "gmachine: Consecutive error limit of %d exceeded, %d total errors",
  688.             MaxErr, nerr + remote_stats.errors);
  689.          done = close = TRUE;
  690.          gstats();
  691.       }
  692.    } /* while */
  693.  
  694. /*--------------------------------------------------------------------*/
  695. /*    Return to caller, gracefully terminating packet machine if      */
  696. /*    requested                                                       */
  697. /*--------------------------------------------------------------------*/
  698.  
  699.    if ( close )
  700.    {
  701.       gspack(CLOSE, 0, 0, 0, rdata);
  702.       return CLOSE;
  703.    }
  704.    else
  705.       return POK;
  706.  
  707. } /*gmachine*/
  708.  
  709.  
  710. /*************** FRAMING *****************************/
  711.  
  712. /*
  713.    g s p a c k
  714.  
  715.    Send a packet
  716.  
  717.    type=type yyy=pkrec xxx=timesent len=length<=PKTSIZE data=*data
  718.    ret(0) always
  719. */
  720.  
  721. static void gspack(int type, int yyy, int xxx, int len, char *data)
  722. {
  723.    unsigned int check, i;
  724.    unsigned char header[HDRSIZE];
  725.  
  726. #ifdef   LINKTEST
  727.    /***** Link Testing Mods *****/
  728.    unsigned char  dpkerr[10];
  729.    /***** End Link Testing Mods *****/
  730. #endif   /* LINKTEST */
  731.  
  732. #ifdef   LINKTEST
  733.    /***** Link Testing Mods - create artificial errors *****/
  734.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  735.    gets(dpkerr);
  736.    if (dpkerr[0] == 's')
  737.       sscanf(&dpkerr[1], "%d", &xxx);
  738.    /***** End Link Testing Mods *****/
  739. #endif   /* LINKTEST */
  740.  
  741.    printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d",
  742.       type, yyy, xxx, len);
  743.    header[0] = '\020';
  744.    type %= 8;
  745.    header[4] = (unsigned char) (type << 3);
  746.    switch (type) {
  747.    case CLOSE:
  748.       break;   /* stop protocol */
  749.    case NAK:
  750.       header[4] += yyy;
  751.       break;   /* reject */
  752.    case SRJ:
  753.       break;
  754.    case ACK:
  755.       header[4] += yyy;
  756.       break;   /* ack */
  757.    case INITC:
  758.       header[4] += nwindows;
  759.       break;
  760.    case INITB:
  761.       header[4] += 1;
  762.       break;   /* pktsiz = 64 (1) */
  763.    case INITA:
  764.       header[4] += maxwindows;
  765.       break;
  766.    case DATA:
  767.       header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  768.       /* havn't set it up for VERY LONG packets with a few
  769.          bytes yet (-128) */
  770.       if (len < PKTSIZE) { /* short packet? */
  771.          header[4] |= 0x40;
  772.          printmsg(7, "data=|%.*s|", len+1, data);
  773.     /* Count byte is handled at a higher level. */
  774.     /* Header construction should probably be handled there too. */
  775.       } else printmsg(7, "data=|%.*s|", len, data);
  776.       break;
  777.    }
  778.    if (type != DATA) {
  779.       header[1] = 9; /* control packet size = 0 (9) */
  780.       check = (0xaaaa - header[4]) & 0xffff;
  781.    } else {
  782.       header[1] = PKTSIZ2; /* data packet size = 64 (2) */
  783.       check = checksum(data, PKTSIZE);
  784.       i = header[4]; /* got to do this on PC for ex-or high bits */
  785.       i &= 0xff;
  786.       check = (check ^ i) & 0xffff;
  787.       check = (0xaaaa - check) & 0xffff;
  788.    }
  789.    header[2] = (unsigned char) (check & 0xff);
  790.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  791.    header[5] = (unsigned char)
  792.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  793.  
  794. #ifdef   LINKTEST
  795.    /***** More Link Testing Mods *****/
  796.    switch(dpkerr[0]) {
  797.    case 'e':
  798.       data[10] = - data[10];
  799.       break;
  800.    case 'h':
  801.       header[5] = - header[5];
  802.       break;
  803.    case 'l':
  804.       return;
  805.    case 'p':
  806.       swrite((char *) header, HDRSIZE);
  807.       if (header[1] != 9)
  808.          swrite(data, PKTSIZE - 3);
  809.       return;
  810.    default:
  811.       break;
  812.    }
  813.    /***** End Link Testing Mods *****/
  814. #endif   /* LINKTEST */
  815.  
  816.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  817.    if (header[1] != 9)
  818.       swrite(data, PKTSIZE);     /* data is always 64 bytes long */
  819.  
  820. } /*gspack*/
  821.  
  822.  
  823. /*
  824.    g r p a c k
  825.  
  826.    Read packet
  827.  
  828.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  829.  
  830.    ret(type)   ok
  831.    ret(EMPTY)  input buf empty
  832.    ret(ERROR)  bad header
  833.  
  834.    ret(EMPTY)  lost packet timeout
  835.    ret(ERROR)  checksum error
  836.    ret(-5)     packet size != 64
  837.  
  838.    NOTE (specifications for sread()):
  839.  
  840.    sread(buf, n, timeout)
  841.       while(TRUE) {
  842.          if (# of chars available >= n) (without dec internal counter)
  843.             read n chars into buf (decrement internal char counter)
  844.             break
  845.     else
  846.        if (time > timeout)
  847.           break;
  848.       }
  849.       return(# of chars available)
  850.  
  851. */
  852.  
  853. static int grpack(int *yyy, int *xxx, int *len, char *data, const int timeout)
  854. {
  855.    static int got_hdr  = FALSE;
  856.    static unsigned char grpkt[PKTSIZE+HDRSIZE];
  857.    static int received = 0;     /* Bytes already read into buffer */
  858.    int needed;
  859.  
  860.    unsigned int type, check, checkchk, i, total;
  861.    unsigned char c, c2;
  862.  
  863.    time_t start;
  864.  
  865.    if (got_hdr)
  866.       goto get_data;
  867.  
  868. /*--------------------------------------------------------------------*/
  869. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  870. /*--------------------------------------------------------------------*/
  871.  
  872.    start = 0;
  873.    while (!got_hdr)
  874.    {
  875.       unsigned char *psync;
  876.  
  877.       needed = HDRSIZE - received;
  878.       if ( needed > 0 )       /* Have enough bytes for header?       */
  879.       {                       /* No --> Read as much as we need      */
  880.          int wait;
  881.  
  882.          if ( start == 0 )    /* First pass through data?            */
  883.          {                    /* Yes --> Set timers up               */
  884.             start = time(nil(time_t));
  885.             wait = timeout;
  886.          } /* if ( start == 0 ) */
  887.          else {
  888.             wait = (int) (time(NULL) - start) - timeout;
  889.             if (wait < 0)     /* Negative timeout?                   */
  890.                wait = 0;      /* Make it no time out                 */
  891.          } /* else */
  892.  
  893.          if (sread((char *) &grpkt[received], needed, wait ) < (unsigned) needed )
  894.                               /* Did we get the needed data?         */
  895.             return EMPTY;     /* No --> Return to caller             */
  896.          received += needed;
  897.       } /* if ( needed < received ) */
  898.  
  899. /*--------------------------------------------------------------------*/
  900. /*            Search for sync character in newly read data            */
  901. /*--------------------------------------------------------------------*/
  902.  
  903.       printmsg(10,"grpack: Have %d characters after reading %d",
  904.                received, needed);
  905.       psync = memchr( grpkt, '\020', received );
  906.       if ( psync == NULL )    /* Did we find the sync character?     */
  907.          received = 0;        /* No --> Reset to empty buffer        */
  908.       else if ( psync != grpkt ) /* First character in buffer?       */
  909.       {                       /* No --> Make it first character      */
  910.          received -= psync - grpkt;
  911.          shifts++;
  912.          memmove( grpkt, psync, received );
  913.                               /* Shift buffer over                   */
  914.       } /* else */
  915.  
  916. /*--------------------------------------------------------------------*/
  917. /*    If we have read an entire packet header, then perform a         */
  918. /*    simple XOR checksum to determine if it is valid.  If we have    */
  919. /*    a valid checksum, drop out of this search, else drop the        */
  920. /*    sync character and restart the scan.                            */
  921. /*--------------------------------------------------------------------*/
  922.  
  923.       if ( received >= HDRSIZE )
  924.       {
  925.          i = (unsigned) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
  926.                         grpkt[4] ^ grpkt[5]);
  927.          i &= 0xff;
  928.          printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  929.             grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  930.  
  931.          if (i == 0)          /* Good header?                        */
  932.             got_hdr = TRUE;   /* Yes --> Drop out of loop            */
  933.          else {               /* No  --> Flag it, continue loop      */
  934.             badhdr++;
  935.             printmsg(2, "*** bad pkt header ***");
  936.             memmove( grpkt, &grpkt[ 1 ], --received );
  937.                               /* Begin scanning for sync character
  938.                                  with next byte                      */
  939.          } /* else */
  940.       } /* if ( received > HDRSIZE ) */
  941.    } /* while */
  942.  
  943. /*--------------------------------------------------------------------*/
  944. /*                       Handle control packets                       */
  945. /*--------------------------------------------------------------------*/
  946.  
  947.    if (grpkt[1] == 9)
  948.    {
  949.       *data = '\0';
  950.       *len = 0;
  951.       c = grpkt[4];
  952.       type = c >> 3;
  953.       *yyy = c & 0x07;
  954.       *xxx = 0;
  955.       check = 0;
  956.       checkchk = 0;
  957.       got_hdr = FALSE;
  958.    }
  959. /*--------------------------------------------------------------------*/
  960. /*                        Handle data packets                         */
  961. /*--------------------------------------------------------------------*/
  962.    else {
  963. get_data:
  964.       total = 8 * (2 << grpkt[1]);
  965.       if (total >  PKTSIZE)
  966.       {
  967.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  968.             total, (int) grpkt[1]);
  969.          received = 0;
  970.          got_hdr = FALSE;
  971.          return(-5);       /* can't handle packet size other than 64 */
  972.       }
  973.  
  974.       needed = total + HDRSIZE - received;
  975.       if ((needed > 0) &&
  976.           (sread(&data[total - needed], needed , timeout) < (unsigned)needed))
  977.          return(EMPTY);
  978.  
  979.       if ( received > HDRSIZE )
  980.          memmove( data, &grpkt[HDRSIZE], received - HDRSIZE);
  981.  
  982.       got_hdr = FALSE;
  983.       type = 0;
  984.       c2 = grpkt[4];
  985.       c = (unsigned char) (c2 & 0x3f);
  986.       *xxx = c >> 3;
  987.       *yyy = c & 0x07;
  988.       i = grpkt[3];
  989.       i = (i << 8) & 0xff00;
  990.       check = grpkt[2];
  991.       check = i | (check & 0xff);
  992.       checkchk = checksum(data, total);
  993.       i = grpkt[4] | 0x80;
  994.       i &= 0xff;
  995.       checkchk = 0xaaaa - (checkchk ^ i);
  996.       checkchk &= 0xffff;
  997.       if (checkchk != check) {
  998.          printmsg(4, "*** checksum error ***");
  999.          memmove( grpkt, data, total );
  1000.                               /* Save data so we can scan for sync   */
  1001.          received = total;    /* Note the amount of the data in buf  */
  1002.          return(ERROR);       /* Return to caller with error         */
  1003.       }
  1004.       *len = total;
  1005.       /* Haven't set it up for very long pkts yet (>128).  RH Lamb */
  1006.       if (c2 & 0x40) {
  1007.          int ii;
  1008.          ii = (data[0] & 0xff);
  1009.          *len = (*len - ii) & 0xff;
  1010.          memmove(data, data + 1, *len);
  1011.       }
  1012.    } /* else */
  1013.  
  1014. /*--------------------------------------------------------------------*/
  1015. /*           Announce what we got and return to the caller            */
  1016. /*--------------------------------------------------------------------*/
  1017.  
  1018.    received = 0;              /* Returning entire buffer, reset count */
  1019.    printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1020.       type, *yyy, *xxx, *len);
  1021.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1022.       check, checkchk, total, data);
  1023.  
  1024.    return(type);
  1025.  
  1026. } /*grpack*/
  1027.  
  1028.  
  1029. /*
  1030.    c h e c k s u m
  1031. */
  1032.  
  1033. static unsigned int checksum(char *data, int len)
  1034. {
  1035.    int i, j;
  1036.    unsigned int tmp, chk1, chk2;
  1037.    chk1 = 0xffff;
  1038.    chk2 = 0;
  1039.    j = len;
  1040.    for (i = 0; i < len; i++) {
  1041.       if (chk1 & 0x8000) {
  1042.          chk1 <<= 1;
  1043.          chk1++;
  1044.       } else {
  1045.          chk1 <<= 1;
  1046.       }
  1047.       tmp = chk1;
  1048.       chk1 += (data[i] & 0xff);
  1049.       chk2 += chk1 ^ j;
  1050.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1051.          chk1 ^= chk2;
  1052.       j--;
  1053.    }
  1054.    return(chk1 & 0xffff);
  1055.  
  1056. } /*checksum*/
  1057.